package cn.net.Reflection;
/*
本类属于测试基本反射。注意：不需要main函数，只需要单元测试即可！！
 */
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
/*
【单元测试方法：是Java测试的最小单位，使用灵活】
语法要求：@Test
         public  void getXXX(没有参数){
         }
测试按钮；旁边绿色三角
 */
public class TestReflect1 {


    @Test //一、通过【单元测试方法】来【获取类的字节码对象】
    public void getClazz() throws Exception {//@Test注解不能用于main方法中
        //第一种：Class.forName()全路径名：包名.类名
        Class<?> student1 = Class.forName("cn.net.Reflection.Student");
       //第二种：类名Student.class
        Class<?> student2 =  Student.class;
        ///第三种：匿名对象new Student().getClass()
        Class<? > student3 = new Student().getClass();

        System.out.println(student1);
        System.out.println(student1.getName());
        System.out.println(student1.getPackage().getName());
        System.out.println(student1.getSimpleName());

    }

    //二、通过【单元测试】来【获取构造方法】
    @Test//格式要求
    public void getConstruct() {
           Class<?>  clazz =Student.class;
        Constructor<?>[] cs = clazz.getConstructors();//获取所有构造方法并放入数组【】
        //3.获取每个构造
        //使用增强for循环完成遍历，在for内获取并打印
        for (Constructor c : cs
             ) {
            System.out.println(c.getName());////获取构造方法的名称
            Class[] types = c.getParameterTypes();//获取构造方法的参数类型,

            System.out.println(Arrays.toString(types));//打印其参数类型//[class java.lang.String, int]
        }

    }

       //三、 : 获取成员方法
    @Test
    public void getFunction() throws Exception {
        Class<?> aClass = Class.forName("cn.net.Reflection.Student");
        Method[] ms = aClass.getMethods();//加s获取所有方法,并放入数组,需要遍历
        //遍历数组；增强for
        for (Method  m:ms
             ) {
            System.out.println(m.getName());//获取成员方法的完整类名
            Class<?>[] types = m.getParameterTypes();//获取方法的参数类型
            System.out.println(Arrays.toString(types));//查看数组并在里面打印显示参数类型
        }
    }
    @Test//四: 获取成员变量
    //注意：成员变量的修饰必须是public才能获取。默认的是私有变量不能获取
    public void getFiled(){
        Class<Student> cls = Student.class;//获取字节码对象
        Field[] fs = cls.getFields();//s获取所有成员变量===>需要遍历
        for (Field f:fs
             ) {
            System.out.println(f.getName());//获取变量名
            System.out.println(f.getType().getName());//获取变量类型

        }
    }

    @Test//五 : 反射创建对象:
    public void  getObject() throws Exception {
        //1.获取字节码对象
        Class<?> clazz = Student.class;

        //2.-----newInstance()方法创建对象Object-----
        Object obj = clazz.newInstance();//触发无参构造创建对象
        System.out.println(obj);/**重写toString()方法对应的Student [name=null,age=0]，否则打印的是地址值*/
        //3.根据参数来指定获取哪个全参构造方法,传入的是参数的字节码对象
        Constructor<?> c = clazz.getConstructor(String.class, int.class);
        Object obj2 = c.newInstance("小艾",20);//执行含参构造创建对象==赋值
        System.out.println(obj2);//Student{name='小艾', age=20}
        /*
        //5.查看对象具体的属性值,或者调用方法,需要把Object强转成指定的子类类型
            为什么要把Object强转成子类类型?因为想要使用子类的特有功能,父类无法使用子类的特有功能
            这个操作叫做向下转型--想使用子类特有功能时需要做此操作
         *///obj2父类类型
        Student s = (Student)obj2;//强转子类类型
        System.out.println(s.name);//小艾
        System.out.println(s.age);//20
        s.eat();//开饭了
        s.play(23);//我今天玩了23个小时代码

    }



}
